#include <CoreFoundation/CoreFoundation.h>
#include <IOKit/IOCFPlugIn.h>
#include <IOKit/usb/IOUSBLib.h>
#include <unistd.h>
#include "something.h"
#include "printInterpretedError.h"
#define VERBOSE 1
#define MATCH_INTERFACE 1
void useUSBInterface(IOUSBInterfaceInterface245 **intf)
{
printf("Now we actually get to do something with this device, wow!!!!\n");
finallyDoSomethingWithThisDevice(intf);
}
UInt32 openUSBInterface(IOUSBInterfaceInterface245 **intf)
{
IOReturn ret;
#if VERBOSE
UInt8 n;
int i;
UInt8 direction;
UInt8 number;
UInt8 transferType;
UInt16 maxPacketSize;
UInt8 interval;
static char *types[]={
"Control",
"Isochronous",
"Bulk",
"Interrupt"};
static char *directionStr[]={
"Out",
"In",
"Control"};
#endif
ret = (*intf)->USBInterfaceOpen(intf);
if(ret != kIOReturnSuccess)
{
printInterpretedError("Could not set configuration on device", ret);
return(-1);
}
#if VERBOSE
ret = (*intf)->GetNumEndpoints(intf, &n);
if(ret != kIOReturnSuccess)
{
printInterpretedError("Could not get number of endpoints in interface", ret);
return(0);
}
printf("%d endpoints found\n", n);
for(i = 1; i<=n; i++)
{
ret = (*intf)->GetPipeProperties(intf, i, &direction, &number, &transferType, &maxPacketSize, &interval);
if(ret != kIOReturnSuccess)
{
fprintf(stderr, "Endpoint %d -", n);
printInterpretedError("Could not get endpoint properties", ret);
return(0);
}
printf("Endpoint %d: %s %s %d, max packet %d, interval %d\n", i, types[transferType], directionStr[direction], number, maxPacketSize, interval);
}
#endif
return(0);
}
IOUSBInterfaceInterface245 **getUSBInterfaceInterface(io_service_t usbInterface)
{
IOReturn err;
IOCFPlugInInterface **plugInInterface=NULL;
IOUSBInterfaceInterface245 **intf=NULL;
SInt32 score;
HRESULT res;
err = IOCreatePlugInInterfaceForService(usbInterface,
kIOUSBInterfaceUserClientTypeID,
kIOCFPlugInInterfaceID,
&plugInInterface,
&score);
(void)IOObjectRelease(usbInterface); if ((kIOReturnSuccess != err) || (plugInInterface == nil) )
{
printInterpretedError("Unable to create plug in interface for USB interface", err);
return(nil);
}
res = (*plugInInterface)->QueryInterface(plugInInterface, CFUUIDGetUUIDBytes(kIOUSBInterfaceInterfaceID245), (LPVOID)&intf);
IODestroyPlugInInterface(plugInInterface);
if (res || !intf)
{
fprintf(stderr, "Unable to create interface with QueryInterface %lX\n", res);
return(nil);
}
return(intf);
}
Boolean isThisTheInterfaceYoureLookingFor(IOUSBInterfaceInterface245 **intf)
{
static Boolean foundOnce = false;
if(foundOnce)
{
fprintf(stderr, "Subsequent interface found, we're only intersted in 1 of them\n");
return(false);
}
foundOnce = true;
return(true);
}
int iterateinterfaces(io_iterator_t interfaceIterator)
{
io_service_t usbInterface;
int err = 0;
IOReturn ret;
IOUSBInterfaceInterface245 **intf=NULL;
usbInterface = IOIteratorNext(interfaceIterator);
if(usbInterface == nil)
{
fprintf(stderr, "Unable to find an Interface\n");
return(-1);
}
while(usbInterface != nil)
{
intf = getUSBInterfaceInterface(usbInterface);
if(intf != nil)
{
if(isThisTheInterfaceYoureLookingFor(intf))
{
err = openUSBInterface(intf);
if(err == 0)
{
useUSBInterface(intf);
ret = (*intf)->USBInterfaceClose(intf);
}
ret = (*intf)->Release(intf);
return(err);
}
}
usbInterface = IOIteratorNext(interfaceIterator);
}
fprintf(stderr, "No interesting interfaces found\n");
IOObjectRelease(usbInterface);
return(-1);
}
void useUSBDevice(IOUSBDeviceInterface245 **dev, UInt32 configuration)
{
io_iterator_t interfaceIterator;
IOUSBFindInterfaceRequest req;
IOReturn err;
err = (*dev)->SetConfiguration(dev, configuration);
if(err != kIOReturnSuccess)
{
printInterpretedError("Could not set configuration on device", err);
return;
}
req.bInterfaceClass = kIOUSBFindInterfaceDontCare;
req.bInterfaceSubClass = kIOUSBFindInterfaceDontCare;
req.bInterfaceProtocol = kIOUSBFindInterfaceDontCare;
req.bAlternateSetting = kIOUSBFindInterfaceDontCare;
err = (*dev)->CreateInterfaceIterator(dev, &req, &interfaceIterator);
if(err != kIOReturnSuccess)
{
printInterpretedError("Could not create interface iterator", err);
return;
}
err = iterateinterfaces(interfaceIterator);
IOObjectRelease(interfaceIterator);
}
SInt32 openUSBDevice(IOUSBDeviceInterface245 **dev)
{
UInt8 numConfig;
IOReturn err;
IOUSBConfigurationDescriptorPtr desc;
err = (*dev)->GetNumberOfConfigurations(dev, &numConfig);
if(err != kIOReturnSuccess)
{
printInterpretedError("Could not number of configurations from device", err);
return(-1);
}
if(numConfig != 1)
{
fprintf(stderr, "This does not look like the right device, it has %d configurations (we want 1)\n", numConfig);
return(-1);
}
err = (*dev)->GetConfigurationDescriptorPtr(dev, 0, &desc);
if(err != kIOReturnSuccess)
{
printInterpretedError("Could not get configuration descriptor from device", err);
return(-1);
}
#if VERBOSE
printf("Configuration value is %d\n", desc->bConfigurationValue);
#endif
err = (*dev)->USBDeviceOpen(dev);
if(err == kIOReturnExclusiveAccess)
{
#if VERBOSE
printf("Exclusive error opening device, we may come back to this later\n");
#endif
return(-2);
}
if(err != kIOReturnSuccess)
{
printInterpretedError("Could not open device", err);
return(-1);
}
return(desc->bConfigurationValue);
}
IOUSBDeviceInterface245 **getUSBDevice(io_object_t usbDevice)
{
IOReturn err;
IOCFPlugInInterface **plugInInterface=NULL;
IOUSBDeviceInterface245 **dev=NULL;
SInt32 score;
HRESULT res;
err = IOCreatePlugInInterfaceForService(usbDevice,
kIOUSBDeviceUserClientTypeID,
kIOCFPlugInInterfaceID,
&plugInInterface,
&score);
if ((kIOReturnSuccess != err) || (plugInInterface == nil) )
{
printInterpretedError("Unable to create plug in interface for USB device", err);
return(nil);
}
res = (*plugInInterface)->QueryInterface(plugInInterface, CFUUIDGetUUIDBytes(kIOUSBDeviceInterfaceID245), (LPVOID)&dev);
IODestroyPlugInInterface(plugInInterface);
if (res || !dev)
{
fprintf(stderr, "Unable to create USB device with QueryInterface\n");
return(nil);
}
#if VERBOSE
{
UInt16 VID, PID, REL;
err = (*dev)->GetDeviceVendor(dev, &VID);
err = (*dev)->GetDeviceProduct(dev, &PID);
err = (*dev)->GetDeviceReleaseNumber(dev, &REL);
printf("Found device VID 0x%04X (%d), PID 0x%04X (%d), release %d\n", VID, VID, PID, PID, REL);
}
#endif
return(dev);
}
int iterateDevices(io_iterator_t deviceIterator)
{
io_object_t usbDevice;
int err = -1;
IOReturn ret;
IOUSBDeviceInterface245 **dev=NULL;
SInt32 config = 0;
int exclusiveErrs, attempts;
for(attempts = 1; attempts < 5; attempts++)
{
exclusiveErrs = 0;
usbDevice = IOIteratorNext(deviceIterator);
if(usbDevice == nil)
{
fprintf(stderr, "Unable to find first matching USB device\n");
return(-1);
}
while(usbDevice != nil)
{
dev = getUSBDevice(usbDevice);
if(dev != nil)
{
config = openUSBDevice(dev);
if(config == -2)
{
exclusiveErrs++;
}
else if(config >= 0)
{
if(config > 0)
{
useUSBDevice(dev, config);
}
else
{
printf("What use is a device with a zero configuration????\n");
}
ret = (*dev)->USBDeviceClose(dev);
}
ret = (*dev)->Release(dev);
}
IOObjectRelease(usbDevice);
if(config >= 0) {
return(0);
}
usbDevice = IOIteratorNext(deviceIterator);
};
if(exclusiveErrs > 0)
{
sleep(1);
IOIteratorReset(deviceIterator);
printf("Trying open again %d\n", attempts);
}
else
{
break;
}
}
return(err);
}
void SignalHandler(int sigraised)
{
printf("we've just been interrupted, I'll try to stop things (%d)\n", sigraised);
stopDoingSomething();
}
int main (int argc, const char * argv[])
{
IOReturn err;
mach_port_t masterPort;
CFMutableDictionaryRef dict;
SInt32 usbVID;
SInt32 usbPID;
#if MATCH_INTERFACE
SInt32 usbConfig;
SInt32 usbIntNum;
#endif
io_iterator_t anIterator;
sig_t oldHandler;
if(argc < 3)
{
#if VERBOSE
int i;
printf("argc %d\n", argc);
for(i= 0; i<argc; i++)
{
printf("argv[%d]:\"%s\"\n", i, argv[i]);
}
#endif
fprintf(stderr, "Usage: filename VID PID\n");
return(-1);
}
usbVID = atoi(argv[1]);
usbPID = atoi(argv[2]);
oldHandler = signal(SIGINT, SignalHandler);
if (oldHandler == SIG_ERR)
fprintf(stderr, "Could not establish new signal handler (err = %d)\n", errno);
err = IOMasterPort(MACH_PORT_NULL, &masterPort);
if(err != kIOReturnSuccess)
{
printInterpretedError("Could not get master port", err);
return(-1);
}
#if MATCH_INTERFACE
dict = IOServiceMatching("IOUSBInterface");
#else
dict = IOServiceMatching("IOUSBDevice");
#endif
if(dict == nil)
{
fprintf(stderr, "Could create matching dictionary\n");
return(-1);
}
CFDictionarySetValue(
dict,
CFSTR(kUSBVendorID),
CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &usbVID)
);
CFDictionarySetValue(dict, CFSTR(kUSBProductID),
CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &usbPID));
#if MATCH_INTERFACE
usbConfig = 1;
usbIntNum = 0;
CFDictionarySetValue(dict, CFSTR(kUSBConfigurationValue),
CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &usbConfig));
CFDictionarySetValue(dict, CFSTR(kUSBInterfaceNumber),
CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &usbIntNum));
#endif
err = IOServiceGetMatchingServices(masterPort, dict, &anIterator);
if(err != kIOReturnSuccess)
{
printInterpretedError("Could not get device iterator", err);
return(-1);
}
#if MATCH_INTERFACE
err = iterateinterfaces(anIterator);
#else
err = iterateDevices(anIterator);
#endif
IOObjectRelease(anIterator);
return err;
}